home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / Development Tools & Languages / AppsToGo / pbClock / Window.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  59.8 KB  |  1,973 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        Window.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1990-1993 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19. /* •••• Except for a couple of places (marked by ••••), this is the only file that
  20. **        changed to turn AppWannabe into pbClock.  Since the changes here are relatively
  21. **        extensive, I didn't mark them with ••••, although they are commented. */
  22.  
  23.  
  24.  
  25. /*****************************************************************************/
  26.  
  27.  
  28.  
  29. #include "App.h"            /* Get the application includes/typedefs, etc.    */
  30. #include "App.defs.h"        /* Get various application definitions.            */
  31. #include "App.protos.h"        /* Get the prototypes for application.            */
  32.  
  33. #ifndef __ERRORS__
  34. #include <Errors.h>
  35. #endif
  36.  
  37. #ifndef __FONTS__
  38. #include <Fonts.h>
  39. #endif
  40.  
  41. #ifndef __LOWMEM__
  42. #include <LowMem.h>
  43. #endif
  44.  
  45. #ifndef __RESOURCES__
  46. #include <Resources.h>
  47. #endif
  48.  
  49. #ifndef __TOOLUTILS__
  50. #include <ToolUtils.h>
  51. #endif
  52.  
  53. #ifndef __UTILITIES__
  54. #include "Utilities.h"
  55. #endif
  56.  
  57.  
  58.  
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. static void        ContentCommon(WindowPtr window, EventRecord *event, short cnum, short action,
  64.                               RGBColor *oldc, RGBColor *newc);
  65. static void        FetchClockValues(FileRecHndl frHndl, short field);
  66. static Boolean    TrackArrowProc(ControlHandle ctl, short part, EventRecord *event);
  67. static Boolean    TrackRadioProc(ControlHandle ctl, short part, EventRecord *event);
  68. static void        SwitchClocks(FileRecHndl frHndl, EventRecord *event, short cnum);
  69. static void        HiliteTabAndReturn(FileRecHndl frHndl);
  70. static Boolean    DigitsOnly(TEHandle teHndl, EventRecord *event, short *handled);
  71. static OSErr    BackLayerProc(LayerObj theLayer, short message);
  72. static OSErr    WorkLayerProc(LayerObj theLayer, short message);
  73. static short    MyGetRadioButtonChoice(WindowPtr window, short famNum);
  74. static short    MyGetButtonVariant(ControlHandle ctl, Boolean *stop);
  75.  
  76. static Point    gArcLocs[60];        /* Used to cache data for speed up. */
  77.  
  78. static LayerObj    gBackLayer[2], gWorkLayer;
  79.     /* These are globals so that they can be created just once.  This speeds up
  80.     ** clock redraws after the first one.  In the DrawClocks function, first
  81.     ** a windowLayer is created that is the size/location of the left clock.
  82.     ** Then, if gWorkLayer hasn't been created yet, it is created as a below-layer
  83.     ** for windowLayer.  I force a depth of 1 for gWorkLayer since the clocks are
  84.     ** only b/w.
  85.     **
  86.     ** Since gWorkLayer and gBackLayer are used as a pair, when gWorkLayer is created,
  87.     ** so is gBackLayer.  If they were already created when DrawClocks is called, then
  88.     ** they are inserted into the windowLayer "chain" just below windowLayer.
  89.     ** Once they are created and attached, they are used, and then just windowLayer
  90.     ** is disposed of, leaving gWorkLayer and gBackLayer around for the next usage.
  91.     **
  92.     ** The only other trick with these guys is that the AppsToGo editor can be used
  93.     ** on this application while it is running.  It is possible that the left and right
  94.     ** clock controls (which are just data controls, and used for their size/position)
  95.     ** are changed.  This would mean that the cached layers could be wrong.  Therefore
  96.     ** in the OpenApplication function (which is called at startup of the application
  97.     ** and at editor restart time), we need to get rid of them if they exist.  By
  98.     ** getting rid of them, the next time that DrawClocks is called, it will create
  99.     ** them again, based on the new size of the clock controls. */
  100.     
  101. typedef struct {
  102.     long    drawTime;
  103.     short    numMoves, timeControl, numRemaining, numTimeControls;
  104. } DrawClocksInfo;
  105.     /* This is the info that the layer procs need.  We put it into a structure
  106.     ** because when we create a layer, we only get to pass in a single refcon
  107.     ** value.  The refcon value will point to one of these structures. */
  108.  
  109.  
  110.  
  111. /*****************************************************************************/
  112.  
  113.  
  114.  
  115. Boolean        gNoDefaultDocument = false;
  116.                     /* Set to true if app should boot with no default document. */
  117.                     /* This tells DTS.Lib..framework what you want. */
  118.  
  119. OSType        gAppWindowType = kDocFileType;    /* Main document type. */
  120. long        gAppWindowAttr = kwAppWindow;    /* Main window attributes. */
  121.  
  122. short        gMinVersion    = kMinVersion;    /* Minimum document version app can support. */
  123. short        gMaxVersion    = kMaxVersion;    /* Maximum document version app can support. */
  124.                                             /* More informing DTS.Lib..framework. */
  125.  
  126. extern long            gTimer;
  127.  
  128. extern short        gPrintPage;                /* Non-zero means we are printing. */
  129.                                             /* DTS.Lib..framework global. */
  130.  
  131. extern RgnHandle    gCursorRgn;                /* We handle cursors here, so we need */
  132. extern CursPtr        gCursorPtr;                /* to know about these things. */
  133.                                             /* Above are DTS.Lib..framework globals. */
  134.  
  135. extern GetButtonVariantProcPtr        gGetButtonVariant;
  136.  
  137.  
  138.  
  139. /*****************************************************************************/
  140. /*****************************************************************************/
  141.  
  142. #ifdef applec
  143. #pragma segment Window
  144. #endif
  145.  
  146. /*****************************************************************************/
  147. /*****************************************************************************/
  148.  
  149.  
  150.  
  151. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  152.  
  153. /* Calculate application specific frame area (Called by DoCalcFrameRgn).
  154. ** You are passed an empty region.  You are supposed to add any custom frame
  155. ** parts that this document uses.  Typically there are no frame portions, as
  156. ** they are accounted for in other ways.  The scrollbars and grow icon will
  157. ** automatically be contributed to the calculation of the frame region.
  158. ** If you use sidebars, these are also added in automatically.  This is only
  159. ** used if the frame region is more complicated than can automatically be
  160. ** handled.  So, almost always, you will simply leave the region empty. */
  161.  
  162. void    CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
  163. {
  164. #ifndef __MWERKS__
  165. #pragma unused (frHndl, window, rgn)
  166. #endif
  167. }
  168.  
  169.  
  170.  
  171. /*****************************************************************************/
  172.  
  173.  
  174.  
  175. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  176.  
  177. /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
  178. ** a window.  Other applications might want to call FindControl, TEClick, etc., to
  179. ** further process the click. */
  180.  
  181. void    ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
  182. {
  183. #ifndef __MWERKS__
  184. #pragma unused (firstClick)
  185. #endif
  186.  
  187.     WindowPtr        oldPort;
  188.     FileRecHndl        frHndl;
  189.     TreeObjHndl        root;
  190.     ControlHandle    ctl;
  191.     short            action, cnum, lr;
  192.     RGBColor        oldc, newc;
  193.  
  194.     GetPort(&oldPort);
  195.     SetPort(window);
  196.     if (gQDVersion) {
  197.         GetBackColor(&oldc);
  198.         newc.red = newc.green = newc.blue = 0xFFFF;
  199.         RGBBackColor(&newc);
  200.     }    /* The window color is non-white, but the control area containing TEControls
  201.         ** is white.  Therefore we have to set the backColor to white before doing
  202.         ** teControl operations, or else we will get some weird results. */
  203.  
  204.     frHndl = (FileRecHndl)GetWRefCon(window);
  205.     root   = (*frHndl)->d.doc.root;
  206.  
  207.     cnum = IsCtlEvent(window, event, &ctl, &action);
  208.  
  209.     switch (cnum) {
  210.  
  211.         case kLeftClockRadio:
  212.         case kRightClockRadio:
  213.         case kBothClocksRadio:
  214.         case kSetClocks:
  215.         case kResetClocks:
  216.         case kStartClocks:
  217.         case kPauseClocks:
  218.         case kTabButton:
  219.         case kReturnButton:
  220.             ContentCommon(window, event, cnum, action, &oldc, &newc);
  221.             break;
  222.  
  223.         default:
  224.             if (cnum) {
  225.                 FetchClockValues(frHndl, 0);
  226.                     /* For any other control click, fetch the values.  FetchClockValues also
  227.                     ** properly closes fields, which is really why we are doing this. */
  228.  
  229.                 if ((cnum >= kTimeControl1Hours) && (cnum < kTimeControlEndRange)) {
  230.                     mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  231.                     mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  232.                     lr = MyGetRadioButtonChoice(window, 0);
  233.                     DrawClock(frHndl, (lr & 0x01));
  234.                     if (lr == 2) DrawClock(frHndl, 1);
  235.                 }
  236.             }
  237.             break;
  238.     }
  239.  
  240.     if (gQDVersion)
  241.         RGBBackColor(&oldc);
  242.  
  243.     SetPort(oldPort);
  244.     return;
  245. }
  246.  
  247. static void    ContentCommon(WindowPtr window, EventRecord *event, short cnum, short action,
  248.                           RGBColor *oldc, RGBColor *newc)
  249. {
  250.     ControlHandle    ctl, cc;
  251.     FileRecHndl        frHndl;
  252.     TreeObjHndl        root;
  253.     short            rs, nm, i;
  254.     Str15            pstr;
  255.     long            diff, timer, t1, t2;
  256.     TEHandle        te;
  257.  
  258.     frHndl = (FileRecHndl)GetWRefCon(window);
  259.     root   = (*frHndl)->d.doc.root;
  260.  
  261.     switch (cnum) {
  262.  
  263.         case kLeftClockRadio:
  264.         case kRightClockRadio:
  265.         case kBothClocksRadio:
  266.             InitContent(frHndl, window);
  267.             if (MyGetRadioButtonChoice(window, 0) == 2) {        /* If "both" radio button selected... */
  268.                 FetchClockValues(frHndl, 0);
  269.                 mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  270.                 mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  271.                     /* If both clocks being set, propagate clock setting. */
  272.             }
  273.             DrawClocks(frHndl);
  274.             break;
  275.  
  276.         case kSetClocks:
  277.             if (gQDVersion) RGBBackColor(oldc);
  278.             DisplayControlSet(window, 'pbc2', kwHideAll);        /* Hide the run clocks controls. */
  279.             if (gQDVersion) RGBBackColor(newc);
  280.             DisplayControlSet(window, 'pbc3', kwShowAll);        /* Show the set clocks controls. */
  281.  
  282.             CNum2Ctl(window, kStartClocksText, &cc);    /* The title of kStartClocksText is used to        */
  283.             pcpy(pstr, (*cc)->contrlTitle);                /* determine if the clocks are running.  Therefore */
  284.             CNum2Ctl(window, kPauseClocks, &cc);        /* flag the clocks as stopped when setting them.   */
  285.             SetStyledCTitle(cc, pstr);
  286.  
  287.             CTEWindActivate(window, true);                /* Reactivate last-active TEControl.         */
  288.             te = CTEFindActive(window);                    /* Show selection range of active TEControl. */
  289.             if (te) CTESetSelect(0, 999, te);
  290.  
  291.             mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  292.             mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  293.                 /* The timeRemaining fields are what is drawn in the clocks, so reset their
  294.                 ** values so that we can display the time that the user is entering. */
  295.  
  296.             mDerefRoot(root)->rightStart = -1;            /* Nobody has started the clocks yet flag. */
  297.             mDerefRoot(root)->numMoves[0] = 0;
  298.             mDerefRoot(root)->numMoves[1] = 0;
  299.             DrawClocks(frHndl);                            /* Show the user the reset values. */
  300.             break;
  301.  
  302.         case kResetClocks:
  303.             mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  304.             mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  305.             mDerefRoot(root)->rightStart = -1;            /* Nobody has started the clocks yet flag. */
  306.             mDerefRoot(root)->numMoves[0] = 0;
  307.             mDerefRoot(root)->numMoves[1] = 0;
  308.             (*frHndl)->d.doc.timer = event->when;        /* Sync up the ticks. */
  309.             CNum2Ctl(window, kPauseClocks, &ctl);
  310.             (*ctl)->contrlValue = 0;                    /* Reset balloon help for control. */
  311.             CNum2Ctl(window, kStopClocksText, &cc);        /* Put clocks in non-pause play mode. */
  312.             pcpy(pstr, (*cc)->contrlTitle);
  313.             SetStyledCTitle(ctl, pstr);
  314.             DrawClocks(frHndl);                            /* Show the user the reset values. */
  315.             HiliteTabAndReturn(frHndl);                    /* Adjust the rest of the controls. */
  316.             break;
  317.  
  318.         case kStartClocks:
  319.             FetchClockValues(frHndl, 0);
  320.                 /* Get the control values and place them into the document.
  321.                 ** This also closes any open field. */
  322.             mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  323.             mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  324.             mDerefRoot(root)->rightStart = -1;            /* Nobody has started the clocks yet flag. */
  325.             mDerefRoot(root)->numMoves[0] = 0;
  326.             mDerefRoot(root)->numMoves[1] = 0;
  327.             DrawClocks(frHndl);                            /* Show the user the reset values. */
  328.             CNum2Ctl(window, kStopClocksText, &ctl);
  329.             pcpy(pstr, (*ctl)->contrlTitle);
  330.             CNum2Ctl(window, kPauseClocks, &ctl);
  331.             (*ctl)->contrlValue = 0;
  332.             SetStyledCTitle(ctl, pstr);
  333.             CNum2Ctl(window, kNoClockButtonClick, &ctl);
  334.             (*ctl)->contrlVis = 0;                        /* Prevent an erase when the kwHideAll is done. */
  335.             HiliteTabAndReturn(frHndl);
  336.             if (gQDVersion) RGBBackColor(oldc);
  337.             DisplayControlSet(window, 'pbc3', kwHideAll);
  338.             if (gQDVersion) RGBBackColor(newc);
  339.             DisplayControlSet(window, 'pbc2', kwShowAll);
  340.             (*frHndl)->d.doc.timer = event->when;        /* Sync up the ticks. */
  341.             break;
  342.  
  343.         case kPauseClocks:
  344.             CNum2Ctl(window, kPauseClocks, &ctl);
  345.             if (ClocksPaused(window)) {
  346.                 (*frHndl)->d.doc.timer = event->when;    /* If currently paused, start 'em up again. */
  347.                 (*ctl)->contrlValue = 0;
  348.                 CNum2Ctl(window, kStopClocksText, &cc);
  349.             }
  350.             else {
  351.                 ContentCommon(window, event, kUpdateClock, action, oldc, newc);
  352.                     /* This is just a cute way to call some common code. */
  353.                 (*ctl)->contrlValue = 2;                /* Clocks stopped has different balloon help. */
  354.                 CNum2Ctl(window, kStartClocksText, &cc);
  355.             }
  356.             pcpy(pstr, (*cc)->contrlTitle);
  357.             SetStyledCTitle(ctl, pstr);
  358.             HiliteTabAndReturn(frHndl);
  359.             break;
  360.  
  361.         case kTabButton:
  362.         case kReturnButton:
  363.             ContentCommon(window, event, kUpdateClock, action, oldc, newc);
  364.                 /* This is just a cute way to call some common code. */
  365.             SwitchClocks(frHndl, event, cnum);
  366.             HiliteTabAndReturn(frHndl);
  367.             break;
  368.  
  369.         case kUpdateClock:        /* No such control.  It's a common utility message. */
  370.             timer = (*frHndl)->d.doc.timer;
  371.             (*frHndl)->d.doc.timer = event->when;
  372.             if (timer) {
  373.                 rs = mDerefRoot(root)->rightStart;
  374.                 nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
  375.                 if (rs > -1) {
  376.                     i  = nm + rs;
  377.                     i &= 0x01;
  378.                     diff = event->when - timer;
  379.                     if (diff < 0) diff = 0;
  380.                     t1 = mDerefRoot(root)->timeRemaining[i];
  381.                     t2 = t1 - diff;
  382.                     if (t2 < 0) t2 = 0;
  383.                     mDerefRoot(root)->timeRemaining[i] = t2;
  384.                     if ((t1 / 60) != (t2 / 60)) DrawClock(frHndl, i);
  385.                 }
  386.             }
  387.             break;
  388.     }
  389. }
  390.  
  391. static void    HiliteTabAndReturn(FileRecHndl frHndl)
  392. {
  393.     WindowPtr        window;
  394.     TreeObjHndl        root;
  395.     short            t, r, rs, nm, lcRunning, rcRunning, pauseHilite, btn;
  396.     ControlHandle    ctl;
  397.     long            t1, t2;
  398.  
  399.     window = (*frHndl)->fileState.window;
  400.     root   = (*frHndl)->d.doc.root;
  401.  
  402.     pauseHilite = 0;
  403.     lcRunning = rcRunning = 0;
  404.     if (ClocksPaused(window)) {
  405.         CNum2Ctl(window, kNoClockButtonClick, &ctl);
  406.         (*ctl)->contrlVis = 255;
  407.             /* This masks out the buttons on the top of the clock.  When this control
  408.             ** is visible, clicks wil go to it, instead of the buttons, which are
  409.             ** behind this control.  This control does nothing with the click.
  410.             ** Therefore the clock buttons are effectively disabled. */    
  411.         t = r = 255;        /* tab and return to be disabled. */
  412.     }
  413.     else {
  414.         CNum2Ctl(window, kNoClockButtonClick, &ctl);
  415.         (*ctl)->contrlVis = 0;        /* Enable clicks on clock buttons. */
  416.         t = r = 0;                    /* Assume tab and return as enabled. */
  417.         rs = mDerefRoot(root)->rightStart;
  418.         if (rs > -1) {
  419.             nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
  420.             if (!((nm + rs) & 0x01)) {
  421.                 r         = 255;        /* return disabled.    */
  422.                 lcRunning = 1;            /* left clock running. */
  423.             }
  424.             else {
  425.                 rcRunning = 1;            /* tab disabled.         */
  426.                 t         = 255;        /* right clock disabled. */
  427.             }
  428.         }
  429.         else pauseHilite = 255;            /* pause button grayed out. */
  430.  
  431.         if (!(t1 = mDerefRoot(root)->timeRemaining[0])) t = 255;    /* If no time on left, gray out tab. */
  432.         if (!(t2 = mDerefRoot(root)->timeRemaining[1])) r = 255;    /* If no time on right, gray out return. */
  433.         if (!(t1 | t2)) pauseHilite = 255;        /* If nobody has moved yet, gray out pause clock button. */
  434.     }
  435.  
  436.     CNum2Ctl(window, kTabButton, &ctl);
  437.     if ((*ctl)->contrlHilite != t) {        /* If control changed... */
  438.         UseControlStyle(ctl);
  439.         HiliteControl(ctl, t);
  440.         UseControlStyle(nil);
  441.     }
  442.     if (!t) {                                /* Do context-sensitive balloon help for tab. */
  443.         if (!r)
  444.             (*ctl)->contrlValue = 0;
  445.         else
  446.             (*ctl)->contrlValue = 2;
  447.     }
  448.     else {
  449.         if (!r)
  450.             (*ctl)->contrlValue = 3;
  451.         else
  452.             (*ctl)->contrlValue = 4;
  453.     }
  454.  
  455.     CNum2Ctl(window, kLeftClock, &ctl);
  456.     (*ctl)->contrlValue = lcRunning;        /* Context sensistve balloon help value for left clock face. */
  457.  
  458.     CNum2Ctl(window, kReturnButton, &ctl);
  459.     if ((*ctl)->contrlHilite != r) {        /* If control changed... */
  460.         UseControlStyle(ctl);
  461.         HiliteControl(ctl, r);
  462.         UseControlStyle(nil);
  463.     }
  464.     if (!r) {                                /* Do context-sensitive balloon help for return. */
  465.         if (!t)
  466.             (*ctl)->contrlValue = 0;
  467.         else
  468.             (*ctl)->contrlValue = 2;
  469.     }
  470.     else {
  471.         if (!t)
  472.             (*ctl)->contrlValue = 3;
  473.         else
  474.             (*ctl)->contrlValue = 4;
  475.     }
  476.  
  477.     CNum2Ctl(window, kRightClock, &ctl);
  478.     (*ctl)->contrlValue = rcRunning;        /* Context sensistve balloon help value for right clock face. */
  479.  
  480.     CNum2Ctl(window, kPauseClocks, &ctl);
  481.     if ((*ctl)->contrlHilite != pauseHilite) {        /* If control changed... */
  482.         (*ctl)->contrlHilite = pauseHilite;
  483.         DoDraw1Control(ctl, false);
  484.     }
  485.  
  486.     btn = 2;
  487.     if ((lcRunning) && (!rcRunning)) btn = 0;
  488.     if ((!lcRunning) && (rcRunning)) btn = 1;
  489.     CNum2Ctl(window, kLeftClock + 2, &ctl);            /* Left clock button. */
  490.     if ((*ctl)->contrlValue != btn) {
  491.         (*ctl)->contrlValue  = btn;
  492.         DoDraw1Control(ctl, false);
  493.     }
  494.  
  495.     if (btn < 2) btn ^= 0x01;
  496.     CNum2Ctl(window, kRightClock + 2, &ctl);        /* Right clock button. */
  497.     if ((*ctl)->contrlValue != btn) {
  498.         (*ctl)->contrlValue  = btn;
  499.         DoDraw1Control(ctl, false);
  500.     }
  501. }
  502.  
  503. short    ClocksPaused(WindowPtr window)
  504. {
  505.     ControlHandle    ctl;
  506.     Str63            p0, p1;
  507.  
  508.     CNum2Ctl(window, kPauseClocks, &ctl);
  509.     pcpy(p0, (*ctl)->contrlTitle);
  510.     CNum2Ctl(window, kStopClocksText, &ctl);
  511.     pcpy(p1, (*ctl)->contrlTitle);
  512.     return(pcmp(p0, p1));        /* If button DOESN'T compare to stopText, then they are stopped. */
  513. }
  514.  
  515. static void    FetchClockValues(FileRecHndl frHndl, short field)
  516. {
  517.     WindowPtr        window;
  518.     TreeObjHndl        root;
  519.     ControlHandle    ctl, ch, cm;
  520.     short            lr1, lr2, i, cn1, cn2;
  521.     Str15            pstr, ph, pm;
  522.     long            h, m, tc1, tc2, tc3;
  523.  
  524.     /* I didn't spend much time typing the below code, or any other part of this sample for
  525.     ** that matter.  I realize that this could probably be done much better/smaller, but
  526.     ** I was coding against a clock, so cut me some slack. */
  527.  
  528.     window = (*frHndl)->fileState.window;
  529.     root   = (*frHndl)->d.doc.root;
  530.  
  531.     lr1 = MyGetRadioButtonChoice(window, 0);
  532.     if (lr1 < 2) lr1 = lr2 = (3 * lr1);
  533.     else {
  534.         lr1 = 0;
  535.         lr2 = 3;
  536.     }        /* Get the left/right clock offsets.  This is based on which control is selected
  537.             ** in the family of radio buttons. (We only have one family -- 0.) */
  538.  
  539.     for (i = 0; i < 3; ++i) {
  540.         cn1 = kTimeControl1Hours +   i * (kTimeControl2Hours   - kTimeControl1Hours);
  541.         cn2 = kTimeControl1Minutes + i * (kTimeControl2Minutes - kTimeControl1Minutes);
  542.         if ((!field) || (field == cn1) || (field == cn2)) {
  543.             CNum2Ctl(window, cn1, &ch);
  544.             CNum2Ctl(window, cn2, &cm);
  545.                 /* Use the delta as an offset.  This is correct, based on the ctlID's I chose. */
  546.                 /* The controls gotten are the hours/minutes control for timeControl i, for whichever
  547.                 ** clock is currently chosen. */
  548.             CTEGetPStr(ch, ph);
  549.             h = p2dec(ph, nil);
  550.             CTEGetPStr(cm,  pm);
  551.             m = p2dec(pm, nil);
  552.             if (m > 59) {
  553.                 ++h;
  554.                 if (h > 99) h = 0;
  555.                 m -= 60;
  556.                 ph[0] = pm[0] = 0;
  557.             }
  558.             if (ph[0] < 2) {
  559.                 pcpypaddec(ph, '0', 2, 2, h);
  560.                 CTEPutPStr(ch, ph);
  561.                 CTESetSelect(0, 2, (TEHandle)GetControlReference(ch));
  562.             }
  563.             if (pm[0] < 2) {
  564.                 pcpypaddec(pm, '0', 2, 2, m);
  565.                 CTEPutPStr(cm, pm);
  566.                 CTESetSelect(0, 2, (TEHandle)GetControlReference(cm));
  567.             }
  568.             mDerefRoot(root)->timeControl[lr1 + i] = (60 * h + m) * 60 * 60;
  569.             mDerefRoot(root)->timeControl[lr2 + i] = (60 * h + m) * 60 * 60;
  570.                 /* Munge the hours and minutes values into a single long tick value. */
  571.         }
  572.     }
  573.  
  574.     if ((!field) || ((field >= kTC1NumMoves) && (field <= kTC3NumMoves))) {
  575.  
  576.         CNum2Ctl(window, kTC1NumMoves, &ctl);
  577.         CTEGetPStr(ctl, pstr);
  578.         tc1 = p2dec(pstr, nil);                        /* TimeControl 1 value. */
  579.  
  580.         CNum2Ctl(window, kTC2NumMoves, &ctl);
  581.         CTEGetPStr(ctl, pstr);
  582.         tc2 = p2dec(pstr, nil);                        /* TimeControl 2 value. */
  583.  
  584.         CNum2Ctl(window, kTC3NumMoves, &ctl);
  585.         CTEGetPStr(ctl, pstr);
  586.         tc3 = p2dec(pstr, nil);                        /* TimeControl 3 value. */
  587.  
  588.         if (!tc1) {
  589.             tc2 = 0;                                /* If no timeControl 1, then no timeControl 2. */
  590.             CNum2Ctl(window, kTC1NumMoves, &ctl);
  591.             UseControlStyle(ctl);
  592.             CTEPutPStr(ctl, "\p");                    /* Change a potential 0 into a nullField. */
  593.             UseControlStyle(nil);
  594.         }
  595.         if (!tc2) {                                    /* Same logic as above. */
  596.             tc3 = 0;
  597.             CNum2Ctl(window, kTC2NumMoves, &ctl);
  598.             UseControlStyle(ctl);
  599.             CTEPutPStr(ctl, "\p");
  600.             UseControlStyle(nil);
  601.         }
  602.         if (!tc3) {                                    /* Same logic as above. */
  603.             CNum2Ctl(window, kTC3NumMoves, &ctl);
  604.             UseControlStyle(ctl);
  605.             CTEPutPStr(ctl, "\p");
  606.             UseControlStyle(nil);
  607.         }
  608.  
  609.         mDerefRoot(root)->numMovesInTimeControl[0] = tc1;    /* Save 'em. */
  610.         mDerefRoot(root)->numMovesInTimeControl[1] = tc2;
  611.         mDerefRoot(root)->numMovesInTimeControl[2] = tc3;
  612.     }
  613. }
  614.  
  615. static Boolean    TrackArrowProc(ControlHandle ctl, short part, EventRecord *event)
  616. {
  617. #ifndef __MWERKS__
  618. #pragma unused (part, event)
  619. #endif
  620.  
  621.     WindowPtr        window, oldPort;
  622.     short            cnum, i, hrAdjust;
  623.     ControlHandle    cc, ccc;
  624.     Str15            pstr, ppp;
  625.     Point            pt;
  626.     Rect            crct;
  627.     long            dt, tc;
  628.  
  629.     /* This be one of the workhorses of this sample.  The arrow controls have a TrackProc
  630.     ** set for them in InitContent.  When the user clicks on an arrow, we end up here.
  631.     ** It is this code's responsibility to track the control, and to update the hour/minute
  632.     ** fields accordingly. */
  633.  
  634.     dt = TickCount() + LMGetDoubleTime();
  635.         /* We don't want to start zooming right away.  This is our delay before repeat. */
  636.  
  637.     window = (*ctl)->contrlOwner;        /* We have to find out who we are talking about. */
  638.     cnum = Ctl2CNum(ctl);
  639.     crct = (*ctl)->contrlRect;            /* That's enough info on where we are. */
  640.  
  641.     GetPort(&oldPort);
  642.     SetPort(window);
  643.  
  644.     CNum2Ctl(window, (cnum & 0xFFFC), &cc);
  645.         /* Note that I carefully selected the ctlID's so that I could do this kind of stuff.
  646.         ** The arrow's ctlID relates it to the TEControl that it adjusts. cc is that field. */
  647.     UseControlStyle(cc);
  648.     CTEGetPStr(cc, pstr);        /* We now have the currelt text from the related TEControl. */
  649.  
  650.     tc = 0x7FFFFFFFL;            /* Use a ridiculous initial value. */
  651.     do {
  652.         if (tc > dt) {            /* First time through, duh... */
  653.             GetMouse(&pt);
  654.             if (PtInRect(pt, &crct)) {        /* Is user actually still on the arrow? */
  655.                 HiliteControl(ctl, 1);
  656.                 hrAdjust = 0;                /* Assume that we won't adjust the hour field. */
  657.                 i = p2dec(pstr, nil);
  658.                 (cnum & 0x01) ? ++i : --i;    /* Up arrow or down arrow hit -- the bits tell us. */
  659.                 if (cnum & 0x04) {            /* If minute field... */
  660.                     if (i < 0) {
  661.                         i = 59;
  662.                         hrAdjust = -1;        /* Roll-over, so we will adjust the hour field, as well. */
  663.                     }
  664.                     if (i > 59) {
  665.                         i = 0;
  666.                         hrAdjust = 1;        /* Roll-over, so we will adjust the hour field, as well. */
  667.                     }
  668.                 }
  669.                 else {
  670.                     if (i < 0)  i = 99;
  671.                     if (i > 99) i = 0;
  672.                 }
  673.                 pcpypaddec(pstr, '0', 2, 2, i);
  674.                 CTEPutPStr(cc, pstr);
  675.                 CTESetSelect(0, 2, (TEHandle)GetControlReference(cc));
  676.                 if (hrAdjust) {                /* If there was a minute roll-over... */
  677.                     i = (cnum ^ 0x04);
  678.                     CNum2Ctl(window, (i & 0xFFFC), &ccc);
  679.                     CTEGetPStr(ccc, ppp);
  680.                     i = p2dec(ppp, nil) + hrAdjust;
  681.                     if (i < 0)  i = 99;
  682.                     if (i > 99) i = 0;
  683.                     pcpypaddec(ppp, '0', 2, 2, i);
  684.                     CTEPutPStr(ccc, ppp);
  685.                     CTESetSelect(0, 2, (TEHandle)GetControlReference(ccc));
  686.                 }
  687.                 SetWindowDirty(window);        /* There was a change, so flag it. */
  688.             }
  689.             else HiliteControl(ctl, 0);
  690.             dt += 6;                        /* Repeat rate is 1/10 of a second. */
  691.         }
  692.         tc = TickCount();
  693.     } while (StillDown());
  694.  
  695.     HiliteControl(ctl, 0);
  696.  
  697.     UseControlStyle(nil);
  698.     SetPort(oldPort);
  699.     return(true);
  700. }
  701.  
  702. static Boolean    TrackRadioProc(ControlHandle ctl, short part, EventRecord *event)
  703. {
  704. #ifndef __MWERKS__
  705. #pragma unused (part)
  706. #endif
  707.  
  708.     WindowPtr                window;
  709.     FileRecHndl                frHndl;
  710.     TreeObjHndl                root;
  711.     static ControlActionUPP    cupp;
  712.  
  713.     window = (*ctl)->contrlOwner;        /* We have to find out who we are talking about. */
  714.     frHndl = (FileRecHndl)GetWRefCon(window);
  715.     root   = (*frHndl)->d.doc.root;
  716.  
  717.     FetchClockValues(frHndl, 0);        /* We're here BEFORE the radio buttons switch. */
  718.     mDerefRoot(root)->timeRemaining[0] = mDerefRoot(root)->timeControl[0];
  719.     mDerefRoot(root)->timeRemaining[1] = mDerefRoot(root)->timeControl[3];
  720.         /* Move clock values where DrawClock can display them. */
  721.  
  722.     if (event->what != mouseDown) return(true);        /* Keypresses "tracked". */
  723.  
  724.     if (!cupp) cupp = (ControlActionUPP)(-1);
  725.     return(TrackControl(ctl, event->where, cupp));
  726. }
  727.  
  728. Boolean    DigitsOnly(TEHandle te, EventRecord *event, short *handled)
  729. {
  730. #ifndef __MWERKS__
  731. #pragma unused (te, handled)
  732. #endif
  733.  
  734.     char    key;
  735.     short    i;
  736.     Boolean    validChar;
  737.  
  738.     key = event->message   & charCodeMask;                /* Cut & paste from some other app I had. */
  739.     i   = event->modifiers & keyCodeMask;
  740.     if (i & cmdKey)                    return(false);
  741.     if (i & optionKey)                return(false);
  742.     if (key == 8)                    return(false);
  743.     if (key == 9)                    return(false);
  744.     if ((key >= 28) && (key <= 31)) return(false);
  745.  
  746.     validChar = false;
  747.     if ((key >= '0') && (key <= '9')) validChar = true;
  748.  
  749.     if (validChar) return(false);
  750.  
  751.     return(true);
  752. }
  753.  
  754.  
  755.  
  756. /*****************************************************************************/
  757.  
  758.  
  759.  
  760. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  761.  
  762. /* DoKeyDown() is first called by the application.  Then if the key isn't a menu
  763. ** key, DoKeyDown() calls this code.  Here are the rules for this function:
  764. **
  765. ** 1) If you handle the key, return(true).  This completes the key handling.
  766. ** 2) If you don't handle the key, you return false.  However, there are two
  767. **    situations for not handling the key:
  768. **      a) You want someone else to.
  769. **      b) You want nobody else to look at the key.
  770. **    This is what the boolean passThrough is for.  If you wish the next window
  771. **    to have a look at the key, set the boolean passThrough to true.  passThrough
  772. **    is already initialized to false, which is the common case, so you only have
  773. **    to worry about setting it true.
  774. **
  775. ** If you have a window that never processes keys and always passes them through,
  776. ** just set the contentKeyProc to nil.  This will indicate to the application
  777. ** framework that all keys should be passed through this window.  DTS.Draw has
  778. ** such a window.  Its palette window doesn't accept keys.  They are passed through
  779. ** to document windows. */
  780.  
  781. Boolean    ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
  782. {
  783. #ifndef __MWERKS__
  784. #pragma unused (passThrough)
  785. #endif
  786.  
  787.     WindowPtr        oldPort;
  788.     FileRecHndl        frHndl;
  789.     TreeObjHndl        root;
  790.     short            cnum, action, i;
  791.     long            lcc, rcc;
  792.     ControlHandle    ctl;
  793.     TEHandle        te1, te2;
  794.     RGBColor        oldc, newc;
  795.  
  796.     GetPort(&oldPort);
  797.     SetPort(window);
  798.     if (gQDVersion) {
  799.         GetBackColor(&oldc);
  800.         newc.red = newc.green = newc.blue = 0xFFFF;
  801.         RGBBackColor(&newc);
  802.     }
  803.  
  804.     frHndl = (FileRecHndl)GetWRefCon(window);
  805.     root   = (*frHndl)->d.doc.root;
  806.  
  807.     /* This is a bit different than the usual AppsToGo ContentKey function.  Since this
  808.     ** app is actually modal (clocks running or not), we need to determine if it is
  809.     ** correct to call IsCtlEvent or not.  If the clocks are running, then the tab
  810.     ** key is used as a clock button.  If we call IsCtlEvent, it will be used to
  811.     ** advance to the next TEControl.  Therefore we need to check if the clocks are
  812.     ** running.  We do this by checking the reset control.  If it is inactive, then
  813.     ** the user clicked on it to start the clock mode. */
  814.  
  815.     te1  = CTEFindActive(window);
  816.     cnum = IsCtlEvent(window, event, nil, &action);
  817.  
  818.     if (cnum == kCRAdvance) {        /* Use the c/r key to advance to next field vertically. */
  819.         ctl = CTEViewFromTE(te1);
  820.         i   = Ctl2CNum(ctl) + 40;
  821.         if (i == 320) i = 204;
  822.         if (i == 324) i = 300;
  823.         if (i == 420) i = 200;
  824.         CNum2Ctl(window, i, &ctl);
  825.         CTEActivate(true, (TEHandle)GetControlReference(ctl));
  826.         CTESetSelect(0, 3, (TEHandle)GetControlReference(ctl));
  827.     }
  828.  
  829.     te2 = CTEFindActive(window);
  830.  
  831.     if (te1 != te2) {        /* Keypress changed field, so close the old one. */
  832.         ctl = CTEViewFromTE(te1);
  833.         FetchClockValues(frHndl, Ctl2CNum(ctl));        /* Specifically fetch the old field. */
  834.         lcc = mDerefRoot(root)->timeRemaining[0] - mDerefRoot(root)->timeControl[0];
  835.         rcc = mDerefRoot(root)->timeRemaining[1] - mDerefRoot(root)->timeControl[3];
  836.         mDerefRoot(root)->timeRemaining[0] -= lcc;
  837.         mDerefRoot(root)->timeRemaining[1] -= rcc;
  838.         if (lcc) DrawClock(frHndl, 0);        /* Draw the left clock if it needs updating. */
  839.         if (rcc) DrawClock(frHndl, 1);        /* Draw the right clock if it needs updating. */
  840.     }
  841.  
  842.     if (action == 2) SetWindowDirty(window);
  843.         /* If a TEControl was changed, dirty the document. */
  844.  
  845.     switch (cnum) {
  846.         case kLeftClockRadio:
  847.         case kRightClockRadio:
  848.         case kBothClocksRadio:
  849.         case kSetClocks:
  850.         case kResetClocks:
  851.         case kStartClocks:
  852.         case kPauseClocks:
  853.         case kTabButton:
  854.         case kReturnButton:
  855.             ContentCommon(window, event, cnum, action, &oldc, &newc);
  856.             break;
  857.     }
  858.  
  859.     if (gQDVersion)
  860.         RGBBackColor(&oldc);
  861.  
  862.     SetPort(oldPort);
  863.     return(true);
  864. }
  865.  
  866. static void    SwitchClocks(FileRecHndl frHndl, EventRecord *event, short cnum)
  867. {
  868.     TreeObjHndl        root;
  869.     short            i, rs, nm, nm1, nm2, nm3;
  870.     long            tc;
  871.  
  872.     root = (*frHndl)->d.doc.root;
  873.  
  874.     rs = mDerefRoot(root)->rightStart;
  875.     nm = mDerefRoot(root)->numMoves[0] + mDerefRoot(root)->numMoves[1];
  876.     if (rs < 0) {                                /* If clocks haven't been started yet. */
  877.         (*frHndl)->d.doc.timer = event->when;
  878.         if (cnum == kTabButton)
  879.             mDerefRoot(root)->rightStart = 1;    /* Start the right clock. */
  880.         if (cnum == kReturnButton)
  881.             mDerefRoot(root)->rightStart = 0;    /* Start the left clock. */
  882.         DrawClocks(frHndl);
  883.         return;
  884.     }
  885.  
  886.     nm1 = mDerefRoot(root)->numMovesInTimeControl[0];    /* Get the timeControl landmarks. */
  887.     nm2 = mDerefRoot(root)->numMovesInTimeControl[1];
  888.     nm3 = mDerefRoot(root)->numMovesInTimeControl[2];
  889.     i   = nm + rs;                        /* Determine which clock is running. */
  890.  
  891.     if (cnum == kTabButton) {            /* If tab was pressed... */
  892.  
  893.         if (!(i & 0x01)) {                /* If tab should have been pressed... */
  894.  
  895.             for (nm = ++mDerefRoot(root)->numMoves[0];;) {        /* for is for break control purposes. */
  896.  
  897.                 if (!nm1) break;
  898.                 tc = mDerefRoot(root)->timeControl[1];
  899.                 if (!tc) break;
  900.                 if (nm == nm1) {
  901.                     mDerefRoot(root)->timeRemaining[0] += tc;
  902.                     break;
  903.                 }
  904.  
  905.                 if (!nm2) break;
  906.                 tc = mDerefRoot(root)->timeControl[2];
  907.                 if (!tc) break;
  908.                 nm1 += nm2;
  909.                 if (nm == nm1) {
  910.                     mDerefRoot(root)->timeRemaining[0] += tc;
  911.                     break;
  912.                 }
  913.  
  914.                 if (!nm3) break;
  915.                 for (;nm1 += nm3 ;) {
  916.                     if (nm < nm1) break;
  917.                     if (nm == nm1) {
  918.                         mDerefRoot(root)->timeRemaining[0] += tc;
  919.                         break;
  920.                     }
  921.                 }
  922.  
  923.                 break;
  924.             }
  925.         }
  926.  
  927.         DrawClock(frHndl, 0);
  928.         DrawClock(frHndl, 1);
  929.     }
  930.  
  931.     if (cnum == kReturnButton) {        /* If return was pressed... */
  932.  
  933.         if (i & 0x01) {                    /* If return should have been pressed... */
  934.  
  935.             for (nm = ++mDerefRoot(root)->numMoves[1];;) {        /* for is for break control purposes. */
  936.  
  937.                 if (!nm1) break;
  938.                 tc = mDerefRoot(root)->timeControl[1 + 3];
  939.                 if (!tc) break;
  940.                 if (nm == nm1) {
  941.                     mDerefRoot(root)->timeRemaining[1] += tc;
  942.                     break;
  943.                 }
  944.  
  945.                 if (!nm2) break;
  946.                 tc = mDerefRoot(root)->timeControl[2 + 3];
  947.                 if (!tc) break;
  948.                 nm1 += nm2;
  949.                 if (nm == nm1) {
  950.                     mDerefRoot(root)->timeRemaining[1] += tc;
  951.                     break;
  952.                 }
  953.  
  954.                 if (!nm3) break;
  955.                 for (;nm1 += nm3 ;) {
  956.                     if (nm < nm1) break;
  957.                     if (nm == nm1) {
  958.                         mDerefRoot(root)->timeRemaining[1] += tc;
  959.                         break;
  960.                     }
  961.                 }
  962.  
  963.                 break;
  964.             }
  965.         }
  966.  
  967.         DrawClock(frHndl, 1);
  968.         DrawClock(frHndl, 0);
  969.     }
  970. }
  971.  
  972.  
  973.  
  974. /*****************************************************************************/
  975.  
  976.  
  977.  
  978. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  979.  
  980. /* Draw application specific content (Called by DoDrawFrame).
  981. **
  982. ** If your application has any custom frame areas, or if it uses sidebars,
  983. ** this is the function that you would put the frame drawing code.  The
  984. ** document scrollbars and grow icon drawing is handled by DTS.framework.
  985. ** Just do the sidebar and custom areas here. */
  986.  
  987. void    DrawFrame(FileRecHndl frHndl, WindowPtr window, Boolean activate)
  988. {
  989.     MoveTo(0, (*frHndl)->fileState.topSidebar - 1);
  990.     LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, (*frHndl)->fileState.topSidebar - 1);
  991.     LineTo((*frHndl)->fileState.leftSidebar - 1 - 16384, 16383);
  992.  
  993.     BeginFrame(window);
  994.     DoDrawControls(window, activate);
  995.     EndFrame(window);
  996. }
  997.  
  998.  
  999.  
  1000. /*****************************************************************************/
  1001.  
  1002.  
  1003.  
  1004. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1005.  
  1006. /* Frees up any application-specific memory in the document.  This is called by
  1007. ** DoFreeDocument, which is called by DisposeDocument().  The application would
  1008. ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
  1009. **
  1010. ** The document may have a bunch of handles off the main handle of the document.
  1011. ** This is where they are freed.  DisposeDocument calls this prior to releasing
  1012. ** the ram for the main handle of the document, so release everything else
  1013. ** here, or you will have a memory leak.
  1014. **
  1015. ** NOTE:  Calling DefaultFreeDocument() frees up all memory used by a
  1016. ** hierarchical document (see TreeObj package). */
  1017.  
  1018. OSErr    FreeDocument(FileRecHndl frHndl)
  1019. {
  1020.     return(DefaultFreeDocument(frHndl));
  1021. }
  1022.  
  1023.  
  1024.  
  1025. /*****************************************************************************/
  1026.  
  1027.  
  1028.  
  1029. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1030.  
  1031. /* Any additional window disposal tasks can be handled here. */
  1032.  
  1033. OSErr    FreeWindow(FileRecHndl frHndl, WindowPtr window)
  1034. {
  1035. #ifndef __MWERKS__
  1036. #pragma unused (window)
  1037. #endif
  1038.  
  1039.     WindowPtr    ww;
  1040.     FileRecHndl    ff;
  1041.  
  1042.     if ((*frHndl)->fileState.sfType == kDocFileType) {
  1043.         for (ww = nil; (ww = GetNextWindow(ww, 0)) != nil;) {
  1044.             ff = (FileRecHndl)GetWRefCon(ww);
  1045.             if ((*ff)->fileState.sfType == kViewHierFileType) {
  1046.                 if ((*frHndl)->d.doc.root == (*ff)->d.doc.root) {
  1047.                     DisposeOneWindow(ww, kClose);
  1048.                     ww = nil;
  1049.                 }
  1050.             }
  1051.         }
  1052.     }
  1053.  
  1054.     return(noErr);
  1055. }
  1056.  
  1057.  
  1058.  
  1059. /*****************************************************************************/
  1060.  
  1061.  
  1062.  
  1063. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1064.  
  1065. /* Image the document into the current port.
  1066. **
  1067. ** The only thing tricky about this function is that it needs to key off of
  1068. ** the global variable gPrintPage.  gPrintPage is the current page that is
  1069. ** being printed.  If gPrintPage is 0, then you are drawing to the window.
  1070. **
  1071. ** For when printing:
  1072. **
  1073. ** If gPrintPage is non-0, that is the page to be printed.  If after imaging
  1074. ** the page there are no more pages, you should set gPrintPage to 0.  This
  1075. ** indicates to the print loop that the end of the document has been reached.
  1076. ** Even if the user indicated in the job dialog to print more pages, setting
  1077. ** gPrintPage to 0 states that the last page has been printed.  This is necessary
  1078. ** because the print loop can't know when printing is done.  The imaging procedure
  1079. ** is the logical one to state when everything has been imaged. */
  1080.  
  1081. OSErr    ImageDocument(FileRecHndl frHndl)
  1082. {
  1083.     WindowPtr    window;
  1084.     RGBColor    oldc, newc;
  1085.  
  1086.     window = (*frHndl)->fileState.window;
  1087.  
  1088.     if (gQDVersion) {
  1089.         GetBackColor(&oldc);
  1090.         newc.red = newc.green = newc.blue = 0xFFFF;
  1091.         RGBBackColor(&newc);
  1092.     }
  1093.  
  1094.     DrawClocks(frHndl);
  1095.     DoDrawControls(window, false);
  1096.         /* It's either a clock or a control, and we don't support printing, so that's it. */
  1097.  
  1098.     if (gQDVersion)
  1099.         RGBBackColor(&oldc);
  1100.  
  1101.     gPrintPage = 0;
  1102.     return(noErr);
  1103. }
  1104.  
  1105. void    DrawClocks(FileRecHndl frHndl)
  1106. {
  1107.     DrawClock(frHndl, 0);
  1108.     DrawClock(frHndl, 1);
  1109.     HiliteTabAndReturn(frHndl);
  1110. }
  1111.  
  1112. void    DrawClock(FileRecHndl frHndl, short clock)
  1113. {
  1114.     WindowPtr        window;
  1115.     TreeObjHndl        root;
  1116.     ControlHandle    ctl;
  1117.     Rect            rct;
  1118.     RgnHandle        oldClip, newClip;
  1119.     LayerObj        windowLayer;
  1120.     DrawClocksInfo    dcInfo;
  1121.     short            activeClock, rs, lr;
  1122.     RGBColor        oldc, newc;
  1123.  
  1124.     window = (*frHndl)->fileState.window;
  1125.     root   = (*frHndl)->d.doc.root;
  1126.  
  1127.     SetPort(window);
  1128.  
  1129.     CNum2Ctl(window, clock + kLeftClock, &ctl);
  1130.     rct = (*ctl)->contrlRect;
  1131.  
  1132.     NewLayer(&windowLayer, nil, nil, window, 0, 0);
  1133.     (*windowLayer)->dstRect = rct;
  1134.  
  1135.     if (!gWorkLayer) {            /* If we don't have offscreen layers yet, make 'em. */
  1136.         NewLayer(&gWorkLayer, windowLayer, WorkLayerProc, nil, 8, 0);
  1137.         NewLayer(&gBackLayer[0], gWorkLayer, BackLayerProc, nil, 1, 0);
  1138.         NewLayer(&gBackLayer[1], gWorkLayer, BackLayerProc, nil, 1, 1);
  1139.         DetachLayer(gWorkLayer);
  1140.         DetachLayer(gBackLayer[0]);
  1141.         DetachLayer(gBackLayer[1]);
  1142.     }        /* Note that on an AppsToGo editor restart, OpenApplication disposes of the
  1143.             ** global offscreen layers and resets them to nil.  This means that this
  1144.             ** code will be executed when the program starts up initially, or whevever
  1145.             ** the AppsToGo editor issues a restart. */
  1146.  
  1147.     activeClock = 0;
  1148.     rs = mDerefRoot(root)->rightStart;
  1149.     if (rs > -1) {
  1150.         lr  = mDerefRoot(root)->numMoves[0];
  1151.         lr += mDerefRoot(root)->numMoves[1];
  1152.         lr += rs;
  1153.         lr &= 0x01;
  1154.         if (clock == lr) ++activeClock;
  1155.     }
  1156.  
  1157.     InsertLayer(gWorkLayer, gBackLayer[activeClock], 0);
  1158.     InsertLayer(windowLayer, gWorkLayer, 0);
  1159.  
  1160.     InvalLayer(windowLayer, rct, false);
  1161.     dcInfo.drawTime = mDerefRoot(root)->timeRemaining[clock];
  1162.     dcInfo.numMoves = mDerefRoot(root)->numMoves[clock];
  1163.  
  1164.     dcInfo.numTimeControls = 1;
  1165.     if (mDerefRoot(root)->numMovesInTimeControl[1]) {
  1166.         if (mDerefRoot(root)->timeControl[1 + (3 * clock)]) {
  1167.             ++dcInfo.numTimeControls;
  1168.             if (mDerefRoot(root)->numMovesInTimeControl[2]) {
  1169.                 if (mDerefRoot(root)->timeControl[2 + (3 * clock)]) {
  1170.                     ++dcInfo.numTimeControls;
  1171.                 }
  1172.             }
  1173.         }
  1174.     }
  1175.  
  1176.     dcInfo.timeControl  = 1;
  1177.     dcInfo.numRemaining = mDerefRoot(root)->numMovesInTimeControl[0] - dcInfo.numMoves;
  1178.     if (dcInfo.numRemaining < 1) {
  1179.         ++dcInfo.timeControl;
  1180.         dcInfo.numRemaining += mDerefRoot(root)->numMovesInTimeControl[1];
  1181.     }
  1182.     if (dcInfo.numRemaining < 1) {
  1183.         ++dcInfo.timeControl;
  1184.         dcInfo.numRemaining += mDerefRoot(root)->numMovesInTimeControl[2];
  1185.     }
  1186.  
  1187.     (*gWorkLayer)->layerData = (long)&dcInfo;
  1188.         /* Now it knows... */
  1189.  
  1190.     OpenRgn();
  1191.     FrameOval(&rct);
  1192.     CloseRgn(newClip = NewRgn());
  1193.     GetClip(oldClip = NewRgn());
  1194.     SetClip(newClip);
  1195.  
  1196.     if (gQDVersion) {
  1197.         GetBackColor(&oldc);
  1198.         newc.red = newc.green = newc.blue = 0xFFFF;
  1199.         RGBBackColor(&newc);
  1200.     }
  1201.  
  1202.     UpdateLayer(windowLayer);        /* Draw the clock. */
  1203.  
  1204.     if (gQDVersion)
  1205.         RGBBackColor(&oldc);
  1206.  
  1207.     SetClip(oldClip);
  1208.     DisposeRgn(oldClip);
  1209.     DisposeRgn(newClip);
  1210.  
  1211.     DisposeLayer(windowLayer);
  1212.         /* This orphans gWorkLayer and gBackLayer, which means that they will be around
  1213.         ** next time this is called, unless OpenApplication is called. */
  1214. }
  1215.  
  1216. static OSErr    BackLayerProc(LayerObj theLayer, short message)
  1217. {
  1218.     OSErr            err;
  1219.     Rect            rct, rr;
  1220.     Point            cc, pp;
  1221.     short            i, j, dh, dv, hh, vv;
  1222.     RgnHandle        rgn;
  1223.  
  1224.     err = noErr;
  1225.  
  1226.     switch (message) {
  1227.         case kLayerInit:
  1228.             err = DefaultLayerProc(theLayer, message);
  1229.             if (!err) {
  1230.                 SetLayerWorld(theLayer);
  1231.                 rct  = GetEffectiveDstRect(theLayer);
  1232.                 cc.h = (rct.left + rct.right) / 2;
  1233.                 cc.v = (rct.top + rct.bottom) / 2;
  1234.                 rgn  = NewRgn();
  1235.                 for (i = 60; i >= 45; --i) {
  1236.                     EraseRect(&rct);
  1237.                     FrameArc(&rct, -6 * i, 1);
  1238.                     if (gQDVersion)
  1239.                         BitMapToRegion(rgn, (BitMapPtr)(*((CGrafPtr)(*theLayer)->layerPort)->portPixMap));
  1240.                     else
  1241.                         BitMapToRegion(rgn, &(*theLayer)->layerPort->portBits);
  1242.                     j = i % 60;
  1243.                     pp.h = (*rgn)->rgnBBox.left;
  1244.                     pp.v = (*rgn)->rgnBBox.top;
  1245.                     gArcLocs[j].h = pp.h;
  1246.                     gArcLocs[j].v = pp.v;
  1247.                     j = 90 - i;
  1248.                     gArcLocs[j].h = pp.h;
  1249.                     gArcLocs[j].v = rct.bottom - (pp.v - rct.top);
  1250.                     j = 60 - j;
  1251.                     gArcLocs[j].h = rct.left + (rct.right - pp.h);
  1252.                     gArcLocs[j].v = rct.bottom - (pp.v - rct.top);
  1253.                     j = 60 - i;
  1254.                     gArcLocs[j].h = rct.left + (rct.right - pp.h);
  1255.                     gArcLocs[j].v = pp.v;
  1256.                 }        /* The above looks awful, but it is relatively simple.  Since the arc code
  1257.                         ** doesn't use trig, if we used trig to compute where the points were, we
  1258.                         ** may be a bit off.  Therefore we will use the arc rendering code itself
  1259.                         ** to determine where the minute marks are on the oval.  To do this, we
  1260.                         ** image a single degree, and then call BitMapToRegion to get a region that
  1261.                         ** is the single pixel.  The bounding box of this region will serve as the
  1262.                         ** coordinate for the minute-mark.  To save time, and to guarantee symmetry,
  1263.                         ** we do only one quadrant, and reflect the coordinate into the other 4. */
  1264.  
  1265.                 if ((*theLayer)->layerData) PenSize(2, 2);
  1266.                 FrameOval(&rct);
  1267.                 PenSize(1, 1);
  1268.                     /* We haven't done a lone EraseRect for the offscreen yet.  This is okay
  1269.                     ** because we did one prior to the FrameArc in the above loop.  Since the
  1270.                     ** FrameArc code does a portion of an oval, the remaining pixel will be
  1271.                     ** properly covered by this FrameOval. */
  1272.  
  1273.                 for (i = 0; i < 60; ++i) {
  1274.                     dh  = cc.h - gArcLocs[i].h;
  1275.                     dh *= 5;
  1276.                     dh /= (cc.h - rct.left);
  1277.                     dv = cc.v - gArcLocs[i].v;
  1278.                     dv *= 5;
  1279.                     dv /= (cc.v - rct.top);
  1280.                     PenSize(2, 2);
  1281.                     hh = gArcLocs[i].h + dh;
  1282.                     vv = gArcLocs[i].v + dv;
  1283.                     if (i % 5)
  1284.                         SetRect(&rr, hh - 1, vv - 1, hh + 1, vv + 1);
  1285.                     else
  1286.                         SetRect(&rr, hh - 2, vv - 2, hh + 2, vv + 2);
  1287.                     PaintOval(&rr);
  1288.                 }
  1289.  
  1290.                 DisposeRgn(rgn);
  1291.                 ResetLayerWorld(theLayer);
  1292.             }
  1293.             break;
  1294.         default:
  1295.             err = DefaultLayerProc(theLayer, message);
  1296.                 /* Default behavior for everything else. */
  1297.             break;
  1298.     }
  1299.  
  1300.     return(err);
  1301. }
  1302.  
  1303. static OSErr    WorkLayerProc(LayerObj theLayer, short message)
  1304. {
  1305.     WindowPtr        window;
  1306.     ControlHandle    ctl;
  1307.     Str63            pstr;
  1308.     OSErr            err;
  1309.     Rect            rct, r;
  1310.     short            dx, dy;
  1311.     Point            cc, pp, p;
  1312.     long            t, h, m, s;
  1313.     RgnHandle        rgn;
  1314.     DrawClocksInfo    dcInfo;
  1315.  
  1316.     err = noErr;
  1317.  
  1318.     switch (message) {
  1319.  
  1320.         case kLayerInit:
  1321.             err = DefaultLayerProc(theLayer, message);
  1322.             break;
  1323.  
  1324.         case kLayerUpdate:
  1325.             DefaultLayerProc(theLayer, message);
  1326.  
  1327.             SetLayerWorld(theLayer);
  1328.  
  1329.             dcInfo = *(DrawClocksInfo *)((*theLayer)->layerData);
  1330.  
  1331.             rct  = GetEffectiveDstRect(theLayer);
  1332.             cc.h = (rct.left + rct.right) / 2;
  1333.             cc.v = (rct.top + rct.bottom) / 2;
  1334.  
  1335.             t = dcInfo.drawTime;
  1336.             if ((t) && (t < 60)) t = 60;        /* Only show 0 when completely out of time. */
  1337.             t  = dcInfo.drawTime / 60;
  1338.             s  = t % 60;
  1339.             t /= 60;
  1340.             m  = t % 60;
  1341.             t /= 60;
  1342.             h  = t;
  1343.  
  1344.             window = (*(*theLayer)->aboveLayer)->layerPort;
  1345.  
  1346.             CNum2Ctl(window, kDigitalDisplay, &ctl);        /* Get the font/size/style set by          */
  1347.             UseControlStyle(ctl);                            /* the AppsToGo editor.                      */
  1348.             TextFont(window->txFont);                        /* UseCotrolStyle gets it, but it puts    */
  1349.             TextSize(window->txSize);                        /* it in the control's port.  Therefore   */
  1350.             TextFace(window->txFace);                        /* we still need to get it from there and */
  1351.             UseControlStyle(nil);                            /* put it into the offscreen.             */
  1352.  
  1353.             pcpypaddec(pstr, '0', 2, 2, h);                    /* Format hh:mm:ss. */
  1354.             pcatchr(pstr, ':', 1);
  1355.             pcatpaddec(pstr, '0', 2, 2, m);
  1356.             pcatchr(pstr, ':', 1);
  1357.             pcatpaddec(pstr, '0', 2, 2, s);
  1358.             r = (*ctl)->contrlRect;
  1359.             MoveTo(r.left, r.bottom - 2);
  1360.             DrawString(pstr);                                /* Draw hh:mm:ss. */
  1361.  
  1362.             CNum2Ctl(window, kMoveDisplay, &ctl);            /* The rest of the text uses a different font. */
  1363.             UseControlStyle(ctl);
  1364.             TextFont(window->txFont);
  1365.             TextSize(window->txSize);
  1366.             TextFace(window->txFace);
  1367.             UseControlStyle(nil);
  1368.  
  1369.             pcpy(pstr, (*ctl)->contrlTitle);                /* Draw the number of moves text. */
  1370.             pcatdec(pstr, dcInfo.numMoves);
  1371.             r = (*ctl)->contrlRect;
  1372.             MoveTo(r.left, r.bottom - 2);
  1373.             DrawString(pstr);
  1374.  
  1375.             if ((dcInfo.numTimeControls > 1) && (dcInfo.numRemaining > 0)) {
  1376.                 CNum2Ctl(window, kTimeControlDisplay, &ctl);
  1377.                 pcpy(pstr, (*ctl)->contrlTitle);
  1378.                 pcatdec(pstr, dcInfo.timeControl);
  1379.                 r = (*ctl)->contrlRect;
  1380.                 MoveTo(r.left, r.bottom - 2);
  1381.                 DrawString(pstr);
  1382.                 (*ctl)->contrlVis = 255;
  1383.                 CNum2Ctl(window, kTimeControlDisplay + 50, &ctl);
  1384.                 (*ctl)->contrlVis = 255;
  1385.  
  1386.                 CNum2Ctl(window, kMovesToMakeDisplay, &ctl);
  1387.                 pcpy(pstr, (*ctl)->contrlTitle);
  1388.                 pcatdec(pstr, dcInfo.numRemaining);
  1389.                 r = (*ctl)->contrlRect;
  1390.                 MoveTo(r.left, r.bottom - 2);
  1391.                 DrawString(pstr);
  1392.                 (*ctl)->contrlVis = 255;
  1393.                 CNum2Ctl(window, kMovesToMakeDisplay + 50, &ctl);
  1394.                 (*ctl)->contrlVis = 255;
  1395.             }
  1396.             else {
  1397.                 CNum2Ctl(window, kTimeControlDisplay, &ctl);
  1398.                 (*ctl)->contrlVis = 0;
  1399.                 CNum2Ctl(window, kTimeControlDisplay + 50, &ctl);
  1400.                 (*ctl)->contrlVis = 0;
  1401.                 CNum2Ctl(window, kMovesToMakeDisplay, &ctl);
  1402.                 (*ctl)->contrlVis = 0;
  1403.                 CNum2Ctl(window, kMovesToMakeDisplay + 50, &ctl);
  1404.                 (*ctl)->contrlVis = 0;
  1405.             }
  1406.  
  1407.             rgn = NewRgn();
  1408.  
  1409.             h = t % 12;
  1410.  
  1411.             OpenRgn();                                /* Draw second hand. */
  1412.             r = rct;
  1413.             InsetRect(&r, 8, 8);
  1414.             FrameOval(&r);
  1415.             CloseRgn(rgn);
  1416.             SetClip(rgn);
  1417.             MoveTo(gArcLocs[s].h, gArcLocs[s].v);
  1418.             LineTo(cc.h, cc.v);
  1419.  
  1420.             OpenRgn();                                /* Draw minute hand. */
  1421.             r = rct;
  1422.             InsetRect(&r, 16, 16);
  1423.             FrameOval(&r);
  1424.             CloseRgn(rgn);
  1425.             SetClip(rgn);
  1426.             pp = gArcLocs[m];
  1427.             p  = gArcLocs[(m + 1) % 60];
  1428.             dx = (p.h - pp.h) * s / 60;
  1429.             dy = (p.v - pp.v) * s / 60;
  1430.             pp.h += dx;
  1431.             pp.v += dy;
  1432.             MoveTo(pp.h, pp.v);
  1433.             LineTo(cc.h, cc.v);
  1434.             MoveTo(pp.h, pp.v);
  1435.             LineTo(cc.h + 1, cc.v);
  1436.             MoveTo(pp.h, pp.v);
  1437.             LineTo(cc.h - 1, cc.v);
  1438.             MoveTo(pp.h, pp.v);
  1439.             LineTo(cc.h, cc.v + 1);
  1440.             MoveTo(pp.h, pp.v);
  1441.             LineTo(cc.h, cc.v - 1);
  1442.  
  1443.             OpenRgn();                                /* Draw hour hand. */
  1444.             r = rct;
  1445.             InsetRect(&r, 50, 50);
  1446.             FrameOval(&r);
  1447.             CloseRgn(rgn);
  1448.             SetClip(rgn);
  1449.  
  1450.             SetRect(&r, cc.h - 2, cc.v - 2, cc.h + 3, cc.v + 3);
  1451.             PaintOval(&r);
  1452.  
  1453.             h *= 5;
  1454.             h += m / 12;
  1455.             pp = gArcLocs[h];
  1456.             p  = gArcLocs[(h + 1) % 60];
  1457.             dx = (p.h - pp.h) * m / 60;
  1458.             dy = (p.v - pp.v) * m / 60;
  1459.             pp.h += dx;
  1460.             pp.v += dy;
  1461.             MoveTo(pp.h, pp.v);
  1462.             LineTo(cc.h, cc.v);
  1463.             MoveTo(pp.h, pp.v);
  1464.             LineTo(cc.h + 1, cc.v);
  1465.             MoveTo(pp.h, pp.v);
  1466.             LineTo(cc.h - 1, cc.v);
  1467.             MoveTo(pp.h, pp.v);
  1468.             LineTo(cc.h, cc.v + 1);
  1469.             MoveTo(pp.h, pp.v);
  1470.             LineTo(cc.h, cc.v - 1);
  1471.             MoveTo(pp.h, pp.v);
  1472.             LineTo(cc.h + 2, cc.v);
  1473.             MoveTo(pp.h, pp.v);
  1474.             LineTo(cc.h - 2, cc.v);
  1475.             MoveTo(pp.h, pp.v);
  1476.             LineTo(cc.h, cc.v + 2);
  1477.             MoveTo(pp.h, pp.v);
  1478.             LineTo(cc.h, cc.v - 2);
  1479.  
  1480.             ClipRect(&rct);
  1481.             DisposeRgn(rgn);
  1482.  
  1483.             ResetLayerWorld(theLayer);
  1484.             break;
  1485.  
  1486.         default:
  1487.             err = DefaultLayerProc(theLayer, message);
  1488.                 /* Default behavior for everything else. */
  1489.             break;
  1490.     }
  1491.  
  1492.     return(err);
  1493. }
  1494.  
  1495.  
  1496.  
  1497. /*****************************************************************************/
  1498.  
  1499.  
  1500.  
  1501. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1502.  
  1503. /* This function does the remaining window initialization.
  1504. **
  1505. ** There may be additional content initialization for the window.  At this point,
  1506. ** you have a window, but it is currently invisible.  If you return noErr, then
  1507. ** the window will be set to the state indicated for that window.  Why this function?
  1508. ** You may wish to add controls to the content of the window.  You may have a
  1509. ** TextEdit record in the content.  All of these sort of things can't be created
  1510. ** until there is a window to contain them.  First a document is read in, and then
  1511. ** if the document creation succeeds, a window is created for that document.
  1512. ** At this point we have a document, and we are on our way to having a window.
  1513. ** All that remains is any additional content initialization.  Do it, return
  1514. ** noErr, and everybody's happy.  If something goes wrong here, return the error,
  1515. ** and the incomplete window will be disposed of. */
  1516.  
  1517. OSErr    InitContent(FileRecHndl frHndl, WindowPtr window)
  1518. {
  1519.     OSErr            err;
  1520.     ControlHandle    ctl;
  1521.     short            i, lr;
  1522.     Str15            pstr;
  1523.     long            t, h, m;
  1524.     TreeObjHndl        root;
  1525.  
  1526.     InitButtonsCtl(4960);
  1527.     gGetButtonVariant = MyGetButtonVariant;
  1528.  
  1529.     CNum2Ctl(window, kLeftClock, &ctl);
  1530.         /* Check to see if the controls have already been added.  This allows us to
  1531.         ** call this after the window has been created. */
  1532.  
  1533.     if (!ctl) {        /* If first time here... */
  1534.         err = AddControlSet(window, (*frHndl)->fileState.sfType, kwStandardVis, 0, 0, nil);
  1535.         if (err) return(err);
  1536.         HiliteTabAndReturn(frHndl);
  1537.     }
  1538.  
  1539.     root = (*frHndl)->d.doc.root;
  1540.  
  1541.     lr = MyGetRadioButtonChoice(window, 0);
  1542.     if (lr == 2) lr = 0;
  1543.     lr *= 3;
  1544.  
  1545.     for (i = 0; i < 3; ++i) {
  1546.  
  1547.         CNum2Ctl(window, kTC1HUpArrow + i * (kTC2HUpArrow - kTC1HUpArrow), &ctl);
  1548.         SetTrackControlProc(ctl, TrackArrowProc);        /* Set the hour up arrow controls to track. */
  1549.  
  1550.         CNum2Ctl(window, kTC1HDnArrow + i * (kTC2HDnArrow - kTC1HDnArrow), &ctl);
  1551.         SetTrackControlProc(ctl, TrackArrowProc);        /* Set the hour down arrow controls to track. */
  1552.  
  1553.         t  = mDerefRoot(root)->timeControl[lr + i];
  1554.         h  = t / (60L * 60 * 60);
  1555.         m  = t - (60L * 60 * 60) * h;
  1556.         m /= (60 * 60);
  1557.  
  1558.         CNum2Ctl(window, kTimeControl1Hours + i * (kTimeControl2Hours - kTimeControl1Hours), &ctl);
  1559.         CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly);
  1560.             /* Filter out non-digits for the hours fields. */
  1561.  
  1562.         UseControlStyle(ctl);
  1563.         pcpypaddec(pstr, '0', 2, 2, h);
  1564.         CTEPutPStr(ctl, pstr);
  1565.         CTESetSelect(0, 2, (TEHandle)GetControlReference(ctl));
  1566.             /* Fill in the field with the hours value. */
  1567.  
  1568.         CNum2Ctl(window, kTC1MUpArrow + i * (kTC2MUpArrow - kTC1MUpArrow), &ctl);
  1569.         SetTrackControlProc(ctl, TrackArrowProc);        /* Set the minute down arrow controls to track. */
  1570.  
  1571.         CNum2Ctl(window, kTC1MDnArrow + i * (kTC2MDnArrow - kTC1MDnArrow), &ctl);
  1572.         SetTrackControlProc(ctl, TrackArrowProc);        /* Set the minute down arrow controls to track. */
  1573.  
  1574.         CNum2Ctl(window, kTimeControl1Minutes + i * (kTimeControl2Minutes - kTimeControl1Minutes), &ctl);
  1575.         CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly);
  1576.             /* Filter out non-digits for the minutes fields. */
  1577.  
  1578.         pcpypaddec(pstr, '0', 2, 2, m);
  1579.         CTEPutPStr(ctl, pstr);
  1580.         CTESetSelect(0, 2, (TEHandle)GetControlReference(ctl));
  1581.             /* Fill in the field with the minutes value. */
  1582.  
  1583.         CNum2Ctl(window, kLeftClockRadio + i, &ctl);
  1584.         SetTrackControlProc(ctl, TrackRadioProc);
  1585.             /* Track the radio buttons (for pre-switch fetch of values). */
  1586.     }
  1587.  
  1588.     for (i = 0; i < 3; ++i) {        /* Fill the numMoves fields. */
  1589.         CNum2Ctl(window, kTC1NumMoves + i * (kTC2NumMoves - kTC1NumMoves), &ctl);
  1590.         CTESetKeyFilter((TEHandle)GetControlReference(ctl), DigitsOnly);        /* Just digits again. */
  1591.         m = mDerefRoot(root)->numMovesInTimeControl[i];
  1592.         if (m) {
  1593.             pcpydec(pstr, m);
  1594.             CTEPutPStr(ctl, pstr);
  1595.             CTESetSelect(0, 3, (TEHandle)GetControlReference(ctl));
  1596.         }
  1597.     }
  1598.  
  1599.     return(noErr);
  1600. }
  1601.  
  1602.  
  1603.  
  1604. /*****************************************************************************/
  1605.  
  1606.  
  1607.  
  1608. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1609.  
  1610. /* The code below assumes that you are using the hierarchical document package.
  1611. ** If you are, the entire hierarchical document is read in with just these two
  1612. ** calls.  If you don't use it, you are on your own.  See DTS.StyleChat for an
  1613. ** example of an application that uses the DTS.framework without the hierarchical
  1614. ** document package. */
  1615.  
  1616. OSErr    ReadDocument(FileRecHndl frHndl)
  1617. {
  1618.     OSErr    err;
  1619.  
  1620.     err = DefaultReadDocument(frHndl);
  1621.     if (!err)
  1622.         DefaultReadDocumentFixup(frHndl);
  1623.  
  1624.     return(err);
  1625. }
  1626.  
  1627.  
  1628.  
  1629. /*****************************************************************************/
  1630.  
  1631.  
  1632.  
  1633. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1634.  
  1635. /* Resize application specific content (Called by ResizeWindow).
  1636. **
  1637. ** This gets called when a user does a zoom or window resizing operation.
  1638. ** It is possible that things in the content need to be resized in conjunction
  1639. ** with the resizing of the window. */
  1640.  
  1641. void    ResizeContent(WindowPtr window, short oldh, short oldv)
  1642. {
  1643. #ifndef __MWERKS__
  1644. #pragma unused (window, oldh, oldv)
  1645. #endif
  1646.  
  1647.     /* See DTS.StyleChat for a sample usage of this function. */
  1648. }
  1649.  
  1650.  
  1651.  
  1652. /*****************************************************************************/
  1653.  
  1654.  
  1655.  
  1656. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1657.  
  1658. /* Scroll application specific frame (Called by DoScrollFrame).
  1659. **
  1660. ** Some applications may need to scroll the "frame" of the document along
  1661. ** with the document contents.  This is common for applications with rulers,
  1662. ** or other similar sidebar items. */
  1663.  
  1664. void    ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
  1665. {
  1666. #ifndef __MWERKS__
  1667. #pragma unused (frHndl, window, dh, dv)
  1668. #endif
  1669. }
  1670.  
  1671.  
  1672.  
  1673. /*****************************************************************************/
  1674.  
  1675.  
  1676.  
  1677. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1678.  
  1679. /* Since the hierarchical document package isn't used by DTS.StyleChat,
  1680. ** this function actually never gets called. */
  1681.  
  1682. void    UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
  1683. {
  1684. #ifndef __MWERKS__
  1685. #pragma unused (frHndl, contOrg, afterUndo)
  1686. #endif
  1687.  
  1688.     /* See DTS.Draw for an example of what you might do here. */
  1689. }
  1690.  
  1691.  
  1692.  
  1693. /*****************************************************************************/
  1694.  
  1695.  
  1696.  
  1697. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1698.  
  1699. /* This function is where you adjust the cursor to reflect the location in the
  1700. ** document or window.  You have the additional input of gCursorRgn to deal
  1701. ** with.  The way that the cursor handling works is as follows:
  1702. ** 1) The application calls DoWindowCursor().
  1703. ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
  1704. **    It looks at the document's windowCursorProc and checks to see if the document
  1705. **    has one.  If the document doesn't have one, then it assumes that that window
  1706. **    always wants an arrow.  If the cursor is over that window, the cursor is set
  1707. **    to an arrow, and we're done.  If the cursor isn't over the window, then the next
  1708. **    window is tried.  If all documents don't have a windowCursorProc, then the cursor
  1709. **    is set to an arrow (for the non-document area of the screen).
  1710. ** 3) If a document has a windowCursorProc, then the proc is called.  The proc's
  1711. **    job is as follows:
  1712. **    a) If the cursor is over a position that is determined by the window, then
  1713. **       the proc removes other areas from gCursorRgn.  Note that it should not
  1714. **       simply set the area to what it "thinks" is the correct area.  This window
  1715. **       may not be the front-most.  Other windows will have already been subtracted
  1716. **       from gCursorRgn.  The resultant gCursorRgn is the correct cursor area,
  1717. **       and should be passed to WaitNextEvent calls in the application (already the case
  1718. **       in EventLoop.c).  Also, the cursor should be set to the correct cursor, of course.
  1719. **       You should also return true, as the cursor has been determined.
  1720. **    b) If the cursor is not over a position for this window, then you should
  1721. **       return.  You will either pass back true or false.  If you don't wish
  1722. **       windows behind this window to have a shot at cursor determination, then
  1723. **       return true.  This states that the cursor is "determined".  It is, in the
  1724. **       sense that no further determination will occur.  If you return false, then
  1725. **       other windows get a shot at determining the cursor.
  1726. **
  1727. ** Setting the cursor to the correct cursor isn't as easy as you would expect.
  1728. ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor.  This is
  1729. ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
  1730. ** more of a problem.  What you will need to do is to call DoSetResCursor() to make the
  1731. ** resource cursor pointer-based.  DoSetResCursor() will set gCursorPtr to nil, and it
  1732. ** also returns the pointer to the permanent copy of the cursor resource.  Just set gCursorPtr
  1733. ** to the return result of DoSetResCursor(), and you will be set. */
  1734.  
  1735. Boolean    WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
  1736. {
  1737.     WindowPtr        oldPort;
  1738.     RgnHandle        contRgn;
  1739.     Rect            rr, teViewRct, contRct;
  1740.     TEHandle        teHndl;
  1741.     ControlHandle    viewCtl;
  1742.     Point            contOrg;
  1743.  
  1744.     if (!window) {
  1745.         SetCursor(gCursorPtr = &qd.arrow);
  1746.         return(true);
  1747.     }
  1748.  
  1749.     oldPort = SetFilePort(frHndl);
  1750.     window = (*frHndl)->fileState.window;
  1751.  
  1752.     GetContentOrigin(window, &contOrg);
  1753.     SetOrigin(contOrg.h, contOrg.v);        /* Scroll position of window. */
  1754.  
  1755.     GetContentRect(window, &contRct);
  1756.         /* This returns the content portion of the window in local coordinates,
  1757.         ** less document scrollbar and sidebar areas. */
  1758.  
  1759.     contRgn = NewRgn();
  1760.     for (viewCtl = nil; ((viewCtl = CTENext(window, &teHndl, viewCtl, 1, false)) != nil);) {
  1761.         teViewRct = (*teHndl)->viewRect;
  1762.         SectRect(&teViewRct, &contRct, &rr);
  1763.         LocalToGlobalRect(&rr);
  1764.         if ((*viewCtl)->contrlVis) {
  1765.             if (!CTEReadOnly(teHndl)) {
  1766.                 RectRgn(contRgn, &rr);
  1767.                 if (PtInRect(globalPt, &rr)) {
  1768.                     gCursorPtr = DoSetResCursor(iBeamCursorSmall);
  1769.                     SectRgn(gCursorRgn, contRgn, gCursorRgn);
  1770.                     DisposeRgn(contRgn);
  1771.                     SetPort(oldPort);
  1772.                     return(true);
  1773.                 }
  1774.                 DiffRgn(gCursorRgn, contRgn, gCursorRgn);
  1775.             }
  1776.         }
  1777.     }
  1778.     SetCursor(gCursorPtr = &qd.arrow);
  1779.     DisposeRgn(contRgn);
  1780.     return(true);
  1781. }
  1782.  
  1783.  
  1784.  
  1785. /*****************************************************************************/
  1786.  
  1787.  
  1788.  
  1789. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1790.  
  1791. /* After the DTS.Lib framework disposes of a window, it calls here.  This is
  1792. ** to give the application a chance to do any additional tasks related to
  1793. ** a window closing.  DTS.StyleChat doesn't have anything else extra to do. */
  1794.  
  1795. void    WindowGoneFixup(WindowPtr window)
  1796. {
  1797. #ifndef __MWERKS__
  1798. #pragma unused (window)
  1799. #endif
  1800. }
  1801.  
  1802.  
  1803.  
  1804. /*****************************************************************************/
  1805.  
  1806.  
  1807.  
  1808. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1809.  
  1810. /* The reverse function of ReadDocument. */
  1811.  
  1812. OSErr    WriteDocument(FileRecHndl frHndl)
  1813. {
  1814.     FetchClockValues(frHndl, 0);
  1815.         /* Have to make sure that the latest info in the controls will be written out. */
  1816.  
  1817.     return(DefaultWriteDocument(frHndl));
  1818. }
  1819.  
  1820.  
  1821.  
  1822. /*****************************************************************************/
  1823.  
  1824.  
  1825.  
  1826. /* •• You don't call this.  DTS.Lib..framework does at open-application time. •• */
  1827.  
  1828. OSErr    DoOpenApplication(void)
  1829. {
  1830.     DisposeLayer(gWorkLayer);        /* May be restarted with new clock sizes. */
  1831.     DisposeLayer(gBackLayer[0]);
  1832.     DisposeLayer(gBackLayer[1]);
  1833.     gWorkLayer = nil;
  1834.     gBackLayer[0] = nil;
  1835.     gBackLayer[1] = nil;
  1836.     return(noErr);
  1837. }
  1838.  
  1839.  
  1840.  
  1841. /*****************************************************************************/
  1842. /*****************************************************************************/
  1843. /*****************************************************************************/
  1844.  
  1845.  
  1846.  
  1847. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1848.  
  1849. Boolean    AdjustMenuItems(WindowPtr window, short menuID)
  1850. {
  1851.     Boolean        redrawMenuBar;
  1852.     MenuHandle    menu;
  1853.  
  1854.     redrawMenuBar = false;
  1855.  
  1856.     switch (menuID) {
  1857.         case mFile:
  1858.             redrawMenuBar = DoAdjustFileMenu(window);
  1859.             break;
  1860.         case mEdit:
  1861.             redrawMenuBar = DoAdjustEditMenu(window);
  1862.             break;
  1863.         default:
  1864.             menu = GetMenuHandle(menuID);
  1865.             if (menu)
  1866.                 (*menu)->enableFlags |= 0xFFFFFFFEL;
  1867.             break;
  1868.     }
  1869.  
  1870.     return(redrawMenuBar);
  1871. }
  1872.  
  1873.  
  1874.  
  1875. /*****************************************************************************/
  1876.  
  1877.  
  1878.  
  1879. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  1880.  
  1881. Boolean    DoMenuItem(WindowPtr window, short menuID, short menuItem)
  1882. {
  1883. #ifndef __MWERKS__
  1884. #pragma unused (window)
  1885. #endif
  1886.  
  1887.     return(DoMenuCommand(menuID, menuItem));
  1888. }
  1889.  
  1890.  
  1891.  
  1892. /*****************************************************************************/
  1893.  
  1894.  
  1895.  
  1896. static short    MyGetRadioButtonChoice(WindowPtr window, short famNum)
  1897. {
  1898.     ControlHandle    nextCtl;
  1899.     short            firstInFam, cnum, chosen;
  1900.  
  1901.     nextCtl = ((WindowPeek)window)->controlList;
  1902.     for (firstInFam = chosen = 0;;) {
  1903.         if (!nextCtl) {
  1904.             if (!chosen) return(-1);
  1905.                 /* If a proper radio button family was passed in, this can't
  1906.                 ** happen.  The -1 is an error that indicates that the
  1907.                 ** requested family didn't exist, or that there was no selected
  1908.                 ** radio of the requested family. */
  1909.             return(chosen - firstInFam);
  1910.         }
  1911.         if (IsButtonsCtl(nextCtl)) {
  1912.             if (GetControlReference(nextCtl) == famNum) {
  1913.                 cnum = Ctl2CNum(nextCtl);
  1914.                 if (!firstInFam)
  1915.                     firstInFam = cnum;
  1916.                 else {
  1917.                     if (firstInFam > cnum)
  1918.                         firstInFam = cnum;
  1919.                 }
  1920.                 if (GetControlValue(nextCtl)) chosen = cnum;
  1921.             }
  1922.         }
  1923.         nextCtl = (*nextCtl)->nextControl;
  1924.     }
  1925. }
  1926.  
  1927.  
  1928.  
  1929. /*****************************************************************************/
  1930.  
  1931.  
  1932.  
  1933. short    MyGetButtonVariant(ControlHandle ctl, Boolean *stop)
  1934. {
  1935.     if (ctl)
  1936.         if (IsButtonsCtl(ctl))
  1937.             return(2);
  1938.  
  1939.     return(-1);
  1940. }
  1941.  
  1942.  
  1943.  
  1944. pascal long    xxx(short varCode, ControlHandle ctl, short msg, long parm);
  1945. pascal long    xxx(short varCode, ControlHandle ctl, short msg, long parm)
  1946. {
  1947.     long    retVal;
  1948.     Rect    rct;
  1949.  
  1950.  
  1951.     retVal = 0;
  1952.  
  1953.     rct = (*ctl)->contrlRect;
  1954.     switch (msg) {
  1955.         case drawCntl:
  1956.             FrameRect(&rct);
  1957.             break;
  1958.  
  1959.         case calcCRgns:
  1960.         case calcCntlRgn:
  1961.         case calcThumbRgn:
  1962.             if (msg == calcCRgns) parm &= 0x00FFFFFF;
  1963.             RectRgn((RgnHandle)parm, &rct);
  1964.             if (msg != calcCRgns) retVal = 1;
  1965.             break;
  1966.     }
  1967.  
  1968.     return(retVal);
  1969. }
  1970.  
  1971.  
  1972.  
  1973.